 /*
 * Copyright (C) 2017-2024 Alibaba Group Holding Limited
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef PVAMRWBDECODER_BASIC_OP_RISCV_DSP_H
#define PVAMRWBDECODER_BASIC_OP_RISCV_DSP_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "normalize_amr_wb.h"

    __inline int16 add_int16(int16 var1, int16 var2)
    {
    int32 L_sum = 0;
    asm volatile(
        "kadd16 %0, %1, %2\n\t"
        :"+r"(L_sum)
        :"r"(var1), "r"(var2)
        :);
    return L_sum;
    }

        __inline int16 sub_int16(int16 var1, int16 var2)
    {
        int32 L_diff = 0;
        asm volatile(
            "ksub16 %0, %1, %2\n\t"
            :"+r"(L_diff)
            :"r"(var1), "r"(var2)
            :);
        return L_diff;
    }

    __inline int16 mult_int16(int16 var1, int16 var2)
    {
        int32 L_product = 0;

        L_product = ((int32) var1 * (int32) var2) >> 15;

        if ((L_product >> 15) != (L_product >> 31))
        {
            L_product = (L_product >> 31) ^ MAX_16;
        }

        return ((int16)L_product);
    }

    __inline  int32 add_int32(int32 L_var1, int32 L_var2)
    {
        int32 L_sum = 0;
        asm volatile(
            "kaddw %0, %1, %2\n\t"
            :"+r"(L_sum)
            :"r"(L_var1), "r"(L_var2)
            :);
        return L_sum;
    }


   __inline  int32 sub_int32(int32 L_var1, int32 L_var2)
    {
        int32 L_diff = 0;
        asm volatile(
            "ksubw %0, %1, %2\n\t"
            :"+r"(L_diff)
            :"r"(L_var1), "r"(L_var2)
            :);
        return L_diff;
    }

    __inline  int32 mul_16by16_to_int32(int16 var1, int16 var2)
    {
        int32 L_mul = 0;

        L_mul  = ((int32) var1 * (int32) var2);

        if (L_mul != 0x40000000)
        {
            L_mul <<= 1;
        }
        else
        {
            L_mul = MAX_32;     /* saturation */
        }

        return (L_mul);

    }


    __inline  int32 mac_16by16_to_int32(int32 L_var3, int16 var1, int16 var2)
    {
        return add_int32(L_var3, mul_16by16_to_int32(var1, var2));
    }

    __inline  int32 msu_16by16_from_int32(int32 L_var3, int16 var1, int16 var2)
    {
        return sub_int32(L_var3, mul_16by16_to_int32(var1, var2));
    }


    __inline int16 amr_wb_round(int32 L_var1)
    {
        if (L_var1 <= (MAX_32 - 0x00008000L))
        {
            L_var1 +=  0x00008000L;
        }
        return ((int16)(L_var1 >> 16));
    }

    __inline int16 amr_wb_shl1_round(int32 L_var1)
    {
        int16 var_out = 0;

        if ((L_var1 << 1) >> 1 == L_var1)
        {
            var_out = (int16)((L_var1 + 0x00004000) >> 15);
        }
        else
        {
            var_out = (int16)(((L_var1 >> 31) ^ MAX_32) >> 16);
        }

        return (var_out);
    }

    __inline int32 mul_32by16(int16 hi, int16 lo, int16 n)
    {
        return (((((int32)hi*n)) + ((((int32)lo*n) >> 15))) << 1);
    }

    __inline int32_t fxp_mac_16by16(int16_t var1,  int16_t var2, int32_t L_add)
    {
        int32_t result = L_add;
        asm volatile (
            "kmabb %0, %1, %2\n\t"
            :"+r"(result)
            :"r"(var1), "r"(var2)
            :);
        return result;
    }


    __inline  int32 fxp_mul_16by16(int16 var1, const int16 var2)
    {
        int32 L_mul = (int32)var1 * var2;

        return L_mul;
    }

    __inline  int32 fxp_mul32_by_16b(int32 L_var1, const int32 L_var2)
    {

        int32 L_mul = (int32)(((int64)L_var1 * (L_var2 << 16)) >> 32);

        return L_mul;
    }


#ifdef __cplusplus
}
#endif


#endif   /*  PVAMRWBDECODER_BASIC_OP_RISCV_DSP_H  */

